

namespace patiya { namespace Sig {

    class Signal {
    };

    // ========================================================================
    // Sender.
    //

    class SenderBase {
    public:
        SenderBase() {
        }

        virtual ~SenderBase() {
        }

    public:
        typedef void (SenderBase::*Function)(Signal*);

        virtual bool isEqualWith(SenderBase*)   = 0;
        virtual void* object()                  = 0;
        virtual Function sendFun()              = 0;        
    };

    template <class T>
    class Sender : public SenderBase {
    public:
        typedef void (T::*SendFun)(Signal*);

        Sender(T* pObj, SendFun sendFun)
            : m_sendFun(sendFun)
            , m_pObj(pObj)
        {
        }

        virtual ~Sender() {
            m_pObj    = 0;
            m_sendFun = 0;
        }

        Sender<T>* clone() {
            Sender<T>* pSender = new Sender<T>(m_pObj, m_sendFun);
            return pSender;
        }
    
        virtual bool isEqualWith(SenderBase* that) {
            return (   that->object()  == this->object()
                    && that->sendFun() == this->sendFun());
        }
   
        virtual void* object() {
            return reinterpret_cast<void*>(m_pObj);
        }

        virtual SenderBase::Function sendFun() {
            return reinterpret_cast<Function>(m_sendFun);
        }

    private:
        Sender(const Sender<T>&);
        Sender<T>& operator = (const Sender<T>&);
        
    private:
        T*          m_pObj;
        SendFun     m_sendFun;
    };

    // ========================================================================
    // Receiver.
    //

    class ReceiverBase {
    public:
        ReceiverBase() {
        }

        virtual ~ReceiverBase() {
        }

    public:
        typedef void (ReceiverBase::*Function)(Signal*);

        virtual void notify(Signal*)            = 0;
        virtual bool isEqualWith(ReceiverBase*) = 0;
        virtual void* object()                  = 0;
        virtual Function receiveFun()           = 0;
    };

    template <class T>
    class Receiver : public ReceiverBase {
    public:
        typedef void (T::*ReceiveFun)(Signal*);

        Receiver(T* pObj, ReceiveFun receiveFun)
            : m_pObj(pObj)
            , m_receiveFun(receiveFun) {
        }        

        virtual ~Receiver() {
            m_pObj       = 0;
            m_receiveFun = 0;
        }

        Receiver<T>* clone() {
            Receiver<T>* pReceiver = new Receiver<T>(m_pObj, m_receiveFun);
            return pReceiver;
        }

        virtual void notify(Signal* pSignal) {
            (m_pObj->*m_receiveFun)(pSignal);
        }

        virtual bool isEqualWith(ReceiverBase* that) {
            return (   that->object()     == this->object()
                    && that->receiveFun() == this->receiveFun());
        }
   
        virtual void* object() {
            return reinterpret_cast<void*>(m_pObj);
        }

        virtual ReceiverBase::Function receiveFun() {
            return reinterpret_cast<Function>(m_receiveFun);
        }

    private:
        Receiver(const Receiver<T>&);
        Receiver<T>& operator = (const Receiver<T>&);

    private:
        T*          m_pObj;
        ReceiveFun  m_receiveFun;
    };

    // ========================================================================
    // ConnectionMgr
    //

    class ConnectionMgr {
    public:        
        typedef std::vector<ReceiverBase*>          Receivers;

        class Connection {
        public:
            Connection(SenderBase* pSender, const Receivers& receivers)
                : m_pSender(pSender)
                , m_receivers(receivers)
            {}
            Connection(Connection& that) 
                : m_pSender(that.sender())
                , m_receivers(that.receivers())
            {
                assert(that.isValid());
                that.m_pSender = 0;
                that.m_receivers.clear();
            }
            ~Connection() {
                if (m_pSender) {
                    delete m_pSender;
                    m_pSender = 0;
                }

                const int number = m_receivers.size();
                for (int i = 0; i < number; ++i) {
                    delete m_receivers[i];
                    m_receivers[i] = 0;
                }
                m_receivers.clear();
            }

        public:
            SenderBase*         sender()       { return m_pSender; }
            Receivers&       receivers()       { return m_receivers; }

            SenderBase*         sender() const { return m_pSender; }
            const Receivers& receivers() const { return m_receivers; }

            void notify(Signal* pSignal) {
                const int number = m_receivers.size();
                for (int i = 0; i < number; ++i) {
                    m_receivers[i]->notify(pSignal);
                }
            }

            void removeReceiverAt(const int index) {
                if (index > -1 && index < (int)m_receivers.size()) {
                    delete m_receivers[index];
                    m_receivers[index] = 0;

                    m_receivers.erase(m_receivers.begin() + index);
                }
            }

            bool isValid() const {
                return (m_pSender && !m_receivers.empty());
            }

            bool isSender(SenderBase* pSender) {
                return m_pSender->isEqualWith(pSender);
            }

            int findReceiver(ReceiverBase* pReceiver) {
                const int number = m_receivers.size();
                for (int i = 0; i < number; ++i) {
                    if (m_receivers[i]->isEqualWith(pReceiver)) {
                        return i;
                    }
                }
                return -1;
            }        

        private:
            SenderBase*     m_pSender;
            Receivers       m_receivers;
        };
        typedef std::vector<Connection>             Connections;
        typedef std::pair<int, int>                 Location;

    private:
        ConnectionMgr() {
        }

        ~ConnectionMgr() {            
            m_connections.clear();
        }

    public:
        static ConnectionMgr* getInstance() {
            static ConnectionMgr s_connectionMgr;
            return &s_connectionMgr;
        }

        template <class TSender, class TSendFun>
        void notify(TSender* pObjSender, TSendFun sendFun, Signal* pSignal) {            
            Sender<TSender> sender(pObjSender, sendFun);
            const int indexOfConnection = findConnection(&sender);
            if (indexOfConnection > -1)
                m_connections[indexOfConnection].notify(pSignal);
        }

        template <class TSender, class TSendFun, class TReceiver, class TReceiveFun> 
        void connect(TSender*   pObjSender,   TSendFun       sendFun,
                     TReceiver* pObjReceiver, TReceiveFun receiveFun)
        {
            Sender<TSender>       sender(pObjSender,      sendFun);
            Receiver<TReceiver> receiver(pObjReceiver, receiveFun);

            // The sender object should be not the same with the receiver object.
            //
            if (sender.object() == receiver.object()) {
                assert(false);
                return;
            }

            const Location location = findLocation(&sender, &receiver);
            if (location.first < 0) {
                // Add this new receiver into a new receivers.
                //
                Receivers receivers;
                receivers.push_back(receiver.clone());

                // Add this new receivers.
                //
                m_connections.push_back(Connection(sender.clone(), receivers));
            } else if (location.first > -1 && location.second < 0) {
                // Add a new receiver.
                //
                m_connections[location.first].receivers().push_back(receiver.clone());
            } else {
                assert(location.first > -1 && location.second > -1);
            }
        }

        template <class TSender, class TSendFun, class TReceiver, class TReceiveFun> 
        void disconnect(TSender*   pObjSender,   TSendFun       sendFun,
                        TReceiver* pObjReceiver, TReceiveFun receiveFun)
        {
            const Location location = findLocation(pObjSender, sendFun, pObjReceiver, receiveFun);

            if (location.first > -1 && location.second > -1) {
                // Remove this receiver from the connection.
                //
                Connection& connection = m_connections[location.first];
                connection.removeReceiverAt(location.second);

                // Remove this connection if it is empty.
                //
                if (!connection.isValid()) {
                    m_connections.erase(m_connections.begin() + location.first);
                }
            }
        }

    private:
        int findConnection(SenderBase* pSender) {
            const int number = m_connections.size();
            for (int i = 0; i < number; ++i) {
                if (m_connections[i].isSender(pSender))
                    return i;
            }
            return -1;
        }

        template <class TSender, class TSendFun, class TReceiver, class TReceiveFun> 
        Location findLocation(TSender*   pObjSender,   TSendFun       sendFun,
                              TReceiver* pObjReceiver, TReceiveFun receiveFun)
        {
            Sender<TSender>       sender(pObjSender,      sendFun);
            Receiver<TReceiver> receiver(pObjReceiver, receiveFun);
            return findLocation(&sender, &receiver);
        }

        Location findLocation(SenderBase* pSender, ReceiverBase* pReceiver) {
            Location location(-1, -1);
            location.first = findConnection(pSender);
            if (location.first > -1)
                location.second = m_connections[location.first].findReceiver(pReceiver);
            return location;
        }

    private:
        Connections     m_connections;
    };

    // ========================================================================
    // Object.
    //

    class Object {
    protected:
        Object() {
        }
        ~Object() {
        }            
    };

    template <class TSender, class TObject = Object>
    class SigSender : public TObject {
    protected:
        SigSender() {
        }
        ~SigSender() {
        }

    public:
        template <class TSendFun>
        void notify(TSendFun sendFun, Signal* pSignal) {
            ConnectionMgr::getInstance()->notify(static_cast<TSender*>(this), 
                                                 sendFun, pSignal);
        }

        template <class TSendFun, class TReceiver, class TReceiveFun>
        void connect(TSendFun sendFun, TReceiver* pReceiver, TReceiveFun receiveFun) {
            ConnectionMgr::getInstance()->connect(static_cast<TSender*>(this), 
                                                  sendFun, pReceiver, receiveFun);
        }

        template <class TSendFun, class TReceiver, class TReceiveFun>
        void disconnect(TSendFun sendFun, TReceiver* pReceiver, TReceiveFun receiveFun) {
            ConnectionMgr::getInstance()->disconnect(static_cast<TSender*>(this), 
                                                     sendFun, pReceiver, receiveFun);
        }
    };

   
}}